{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# KNN"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "模型准确率: 1.0000\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAA1IAAAIfCAYAAAB6l+0BAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjMsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvZiW1igAAAAlwSFlzAAAPYQAAD2EBqD+naQAAOcNJREFUeJzt3QmYnePdP/A7e6QSJBQhiKUq2qDEa9+KtMT28iJaWvvSWkrVUktsrfIGpUotldKot7R2VdTWqrYvIrUrEtKilaosQoxk/tfv/r9nrpPJzGRuTczMOZ/PdT2dOc85c+Y5555Tzze/+/493RobGxsTAAAA7da9/Q8FAAAgCFIAAACFBCkAAIBCghQAAEAhQQoAAKCQIAUAAFBIkAIAACgkSAEAABQSpACAYh988EFHHwJAhxKkAGiX2bNnp7feeivNmDEjvf/+++3a3n333fTPf/6z6TnmzJnT7p+t3hobG4uPN45z9OjRaeLEifPs/8EPfpC++tWv5tezIJMmTWrxcS+99FJ+/lKHH354uvrqq/PrOfDAA9M111yTPopp06alzTffPD3wwAPFP/uPf/wjnXTSSfm1fVQ77LBDPv5S9913X5o1a1bT7QkTJuR9AF2RIAVAu/z2t79Nn/zkJ9OAAQPSYost1q5t8cUXT+uss07Tc0SIaO/PVm9///vfi4/39ttvTzfccEMOHVE9qYSxJ598Mp/A9+nTJ9+O/RGW5s6dO99znHDCCemLX/zifPu/973vpbXWWit9+OGHLf7uCEjNQ06E0CuvvDJNmTIldevWLa277rrp4IMPTvfff3+Lz/Hcc8/lwDZ58uS8xfevv/56vu/iiy9Ozz//fH6OtsycOXO+Y4zxu+SSS9L48ePn2R+vvxJcKyIIx883D7JbbbVVuvHGG+cJyZXniPeypfAZx7Lrrrum4447rmnftddem0499dQ2XwNAZyVIAXSwBx98MJ9Yxwl+xTnnnJO6d++efv3rX+eT6Lh/n332mefnVllllVxZqXy/0kor5YpPRdwX+xeWzTbbLIeACDX/+te/5tl23333tP7668+3f+rUqemxxx5reo5KeIlqSHu2cePG5ccvscQSTa+pOjzECfvw4cPTmmuumU/Uq/3sZz9LG2+8cXrllVfy7433M97HCHN//vOf8/exxf6+ffumZ599dr7XHPt22WWXefZFqLjnnnvysfTs2bPF9yqef+edd05//OMfm/b96Ec/yr8rqlLhyCOPTOeff376zGc+0xRAGhoamh4fP/+5z30urbrqqjm0xeuOABeB6txzz82PHzp0aOrfv39+HT/5yU/mO4547giiSy65ZFp66aXzttxyy+XXe9FFFzXtiy0CVr9+/fJzV6y88sqpV69eTe9dZYuAGb8/fq56f48ePfJzf/vb357vWK666qr89eyzz57n7yF+ptrLL7/8kSqQAB+3lv8LAECH+d///d80ZsyY9M1vfjONHDkyB6nwi1/8IoeYZZddtsWfi5Bz6623pv/8z/9cJMcVJ8grrrjifPsfeeSR9Mtf/jJP0YoT9rZUTpoj4EXlo3fv3vkkvbkIhLFVXmuczLfkW9/6VnrxxRfTo48+mqtfFU8//XS68847cwUoQt7222/fdNK+9957p0984hM5UIWouEQIGzx4cNPPR4iL/X/5y19ySIvwEj8bwSWC72uvvZZP9i+//PKmn4kgG1PewoUXXpinsEU166GHHkqrr756rgJFUIogU+3YY49t+j6O96CDDsrfx++O9yhCZIxrvIYILxFot9lmm7wv3rsIPlF522+//VqsasUUxKgkVt7XTTfdND/Hf//3f+cAV3n/33vvvfTMM8/ME1TjbzHGKP7u4vVFFSymFD7xxBNpyJAh6ZRTTsm/I/4247XF80f1L8JdtdgX78lXvvKVNGjQoNSaqIBtt912+fiiWgXQmalIAXQicSL5pS99KVd3oirV/GQ0qhptifU/H6cIC/vvv3+uZMTJfYlPf/rTOZxUVzQqW1R6vvOd77T581Gti3By3nnnpfXWW2+e+84666wcdCI0xEl9hKQ4gY+gF6FpmWWWyd9XKjUR7CIwVMTPfepTn8rveYShNdZYI2200Ub5vghgAwcOzL8/qiyxnXnmmfOEqvDDH/4wB+Hp06fnylOsTYrnrVTr4rgjjMT3cd9f//rXHPKqVap58XPhiCOOSO+8806elhcBKF7L2LFj0xlnnJHft+ai6hRVqbvvvjvfjr+pCGMR3v70pz/lSlesIYtj2HHHHXPorF77FcExfscmm2ySbr755qagvNRSS+X3LcJ1hNyYPrnFFlukp556KlfQ4v2tFpW0CJ8jRoxodTxjvCJovf322+kb3/hGm2MP0BkIUgCdyFFHHZVPqmNaWvMq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bhgVq45epAYAANSudgepuO5SBJeTTz45b5MmTcrd7yJMXXbZZWnjjTfOj5szZ84iXSAWU/daa50e7dGrW6QDAAB0aJBaddVV84VvKyLM3HDDDenaa6/NbcOjc16Ii/VGK3EAAIBa1b3kwXEB3i9+8Yv5+w8//DDdeOONeY1UNICotC2M9UlxHwAAQK0qClLdu3fP15OqrG2qXNQ2GlBULowb++MrAABArWp34omL3P7zn//MzSZCrIPq0aNH/j465YXo5BcbAABAqvcg9eabb6Ztt902tySPMBUtyiv74/tYFxVfm3fgAwAAqNupfVFl2nfffdPZZ5+d+vfvny655JJ80dtoMBHfDx48OH+NDQAAoNa1qyK17LLLpj333DN/36dPn3ydpsqUvvg+2qJX9gEAANS6dgWpF198MV+fKTr2xVqpa665Jk/jmzlzZvrxj3+c3n777aZ9scX3+++//6I/egAAgM46te9Tn/pUeuKJJ9J6662XO/IdeOCB6YQTTkibbrppuv3229PnPve5dNttt+XvR40ala8vBQAAkOq9a180k4jt1FNPTVdccUUaM2ZMnvJ3+eWXL9ojBAAA6GSKL/h03XXXpaFDh6ann346vfPOO+nnP/95Wn311XNVCgAAoB4UXZD3ggsuyBfhbWhoyNWoNddcM/39739Pe+21VxoxYkQaN25cmj179qI7WgAAgK4UpB577LE0duzY9PDDD6dddtmlaf+RRx6Zm1HEmqlzzjkn/cd//MeiOlYAAICuNbVvgw02SM8991waMGBAi9eZ2mOPPdLOO++cXnrppYV9jAAAAF13al9LIapa7969c5t0AACAWlYUpAAAABCkAAAAiglSAAAAhQQpAACAQoIUAABAIUEKAACgkCAFAABQSJACAAAoJEgBAAAUEqQAAAAKCVIAAACFBCkAAIBCghQAAEAhQQoAAKCQIAUAAFBIkAIAACgkSAEAABQSpAAAAAoJUgAAAIUEKQAAgEKCFAAAQCFBCgAAoJAgBQAAUEiQAgAAKCRIAQAAFBKkAAAACglSAAAAhQQpAACAQoIUAABAIUEKAACgkCAFAABQSJACAAAoJEgBAAAUEqQAAAAKCVIAAACFBCkAAIBCghQAAEAhQQoAAKCQIAUAAFBIkAIAACgkSAEAABQSpAAAAAoJUgAAAIUEKQAAgEKCFAAAQCFBCgAAoJAgBQAAUEiQAgAAKCRIAQAAFBKkAAAACglSAAAAhQQpAACAQoIUAABAIUEKAACgkCAFAABQSJACAAAoJEgBAAB0lSD19NNPpxEjRqSllloqHX/88amxsbHNxzc0NOTHrbTSSmn55ZdPp512Wvrwww/zffGzhx9+eBo4cGBacskl01e/+tX03nvvfUyvBAAAqDcdEqRmz56ddtppp7T++uunxx57LD377LNp3Lhxbf7MGWeckX71q1+lu+++O911111p/PjxeV+47rrr0gsvvJAmTJiQfvvb36Znnnkmffe73/2YXg0AAFBvOiRIRSCaNm1auuCCC9Jqq62WvvOd76Srr766zZ+59tprc3AaNmxYWm+99dJxxx2Xbr311nzfn/70p7THHnuklVdeOX32s59Nu+66a3rppZc+plcDAADUm54d8UsnTpyYNtpoo9SvX798e/jw4bkq1ZapU6fmaX0VPXr0yFtYe+21c1Vq9913T++//3664YYb0rHHHttmRSy2iunTpzdNH4ytLZX7F/Q4ui5jXB+Mc+0zxvXBONc+Y1wfGjrROLf3GLo1Lmhx0iIQ1aQIPJdeemnTvmWWWSa9+OKLec1USzbbbLO01VZbpbPPPjvNmTMnbbnllmmTTTZJ5513Xn6xMU3wqaeeyo+NaYO33HJL6t695YLbmDFjmqYFVrv++uubwh0AAFB/Zs2alfbZZ588g27AgAGdqyLVs2fP1KdPn3n29e3bNx90a0EqQteoUaPyNL6XX345vfbaa7kKFb7//e/nJhOvvvpq6tatWzr00ENzY4qxY8e2+FwnnXTSPBWrqEgNGTIkbb/99m2+WSFC27333pu222671KtXr4/w6unsjHF9MM61zxjXB+Nc+4xxfWjoRONcma22IB0SpKK7XnTtqzZjxozUu3fvVn9mnXXWSZMnT07PP/982nfffdP++++fhg4dmu+LxhNnnnlm09S/aDQRFavWglSEuOZBLsSgtXfgSh5L12SM64Nxrn3GuD4Y59pnjOtDr04wzu39/R0SpKLt+ZVXXtl0e9KkSXnNUgSstsSaqKhaRYe+O+64o2n/3Llz0z/+8Y+m22+++Wae/gcAALAodEiQ2mKLLXLJ7JprrsmVpejat+222+ag9M4776T+/fs3NZJoLq4fFWusBg8e3LRv8803T+eee27+mQ8++CB9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fJ5ryJAhQ9KXvvSl/H1DQ0O68MIL02677dYlP8s9O/oAuorp06fP8x/qWOTYo0ePPEc35nHS9cWHuvLBDj/84Q/zmMfYDxgwoEOPjYV/ku0zXft8pmv/BPvYY49NL730ks9yjTr99NPTJz7xiTyFs1evXj7PNWbixIlpm222Sb17985TOs8666wu91lWkWqn+JePPn36zLOvb9++adasWR12TCxan/zkJ9PcuXPTG2+80dGHwiLgM11/fKZr8wTbZ7k23X///XntzPXXX59DVHM+z13f8OHD0z333JMry131syxItdPAgQPTW2+9Nc++GTNm5BRNbYiFjvF/2BWPPvpo6t69ey5BU3t8pmufz3R9nGD7LNeeSZMmpdGjR+dxHjZsWN7n81x7unXrlhtL/OQnP0m//OUvu+Rn2dS+dopWjLHOovpDHt1FYtCpDeuss0465ZRTcpegOXPmpCOPPDLtt99+TXN1qS0+07XPZ7o+TrB9lmvLe++9l9fD7bLLLnndzMyZM5uqFz7PteGhhx5Kd9xxRzr//PPz7QhKEarWWmutrvdZ7uhuF11FQ0ND4zLLLNP44x//ON8+6KCDGkeNGtXRh8VCduKJJzYuscQSjQMHDmw86qijGmfOnNnRh8RCVN3RzWe69sc4+EzXjlmzZjUOGzas8eCDD26cMWNG0/bBBx/4LNeQW265JX+Om2/xufZ5rg2vv/5644ABA3IXzujgt99++zV+4Qtf6JL/Xe4W/9PRYa6ruO222/K/hC222GK5nPzggw82/YsY0PnFv3jFv3DFRQCDzzR0rYvx7rrrrvPtj890dHHzWYau4957703HHHNMmjJlSho5cmRuHrLMMst0uf8uC1KF3nzzzfT444/n9oyDBg3q6MMB/k0+01AbfJahNrzZhT7LghQAAEAhXfsAAAAKCVIAAACFBCkAAIBCghQA/J+33357nttxvZpp06Z12PEA0HkJUgDwfzbeeON08cUXz9Nae8kll8xfAaCaIAVAXRg3blxad911m26PHTs2LbvssrnVbvjTn/6U3nrrrbTSSiulFVdcMV9vbKuttsr3bb311vn2kCFD0sknn9xhrwGAzqNnRx8AAHzcnnzyyXTKKaekW265JS233HJ535lnnpkOOOCAtNNOO6Udd9wx9ezZMz3yyCNpjz32SJMnT86P+fDDD5OrhgAQVKQAqCuzZs1Ko0ePTkceeWQaOXJk3nffffelO++8M4eqHj16pB/96EdpxIgRaf/990/vvPNO2mCDDfJ22WWXpV69enX0SwCgExCkAKgrxx57bOrfv38655xz8u0ISgcffHCe5lfxj3/8I2277bbpL3/5S3r//ffTY489litTMfUPAIKpfQDUjRdffDFNnDgxV5sqlaUHHnggr4kaPnx40+O6d++eq1I33XRT074IXF//+tc75LgB6HxUpACoG++99146//zz05///Od0++2353277bZbuuuuu1K3bt3meeyhhx6aXnrppabtm9/8ZgcdNQCdkYoUAHVj2LBhORBF84jTTz89jRo1KgeomOrX3NVXX53uuOOOpttTp05Nhx122Md8xAB0VipSANSNynS+k046KT377LPp5ptvbvWxBx54YHr66aebtmOOOeZjPFIAOjtBCoC6s8IKK6SDDjoojRkzptV25lGR+sxnPtO0XXTRRR/7cQLQeQlSANSlqEpF84kbb7wx354zZ06+TtQHH3zQZkUq7nctKQC6NfqvAQDk4DR48OB0xRVXpD59+uTOfc3FfzJnz56dpwUOHDiwQ44TgM5BkAIAAChkah8AAEAhQQoAAKCQIAUAAFBIkAIAACgkSAEAABQSpAAAAAoJUgAAAIUEKQAAgEKCFAAAQCrz/wBHuhf2nBzbWQAAAABJRU5ErkJggg==",
      "text/plain": [
       "<Figure size 1000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# k-近邻算法\n",
    "\n",
    "# k-近邻算法（k-Nearest Neighbors，KNN）是一种基本的分类与回归方法\n",
    "# 其核心思想是：如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别，则该样本也属于这个类别\n",
    "\n",
    "# 导入必要的库\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "from sklearn.neighbors import KNeighborsClassifier\n",
    "from sklearn.model_selection import train_test_split\n",
    "from sklearn.datasets import load_iris\n",
    "from sklearn.metrics import accuracy_score\n",
    "\n",
    "# 加载示例数据集（鸢尾花数据集）\n",
    "iris = load_iris()\n",
    "X = iris.data\n",
    "y = iris.target\n",
    "\n",
    "# 划分训练集和测试集\n",
    "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)\n",
    "# 这行代码使用sklearn的train_test_split函数将数据集分为训练集和测试集\n",
    "# X_train: 特征训练集，包含70%的原始数据\n",
    "# X_test: 特征测试集，包含30%的原始数据\n",
    "# y_train: 标签训练集，对应X_train中样本的类别\n",
    "# y_test: 标签测试集，对应X_test中样本的类别\n",
    "# test_size=0.3: 设置测试集占总数据的30%\n",
    "# random_state=42: 设置随机种子，确保每次运行代码时得到相同的划分结果\n",
    "\n",
    "# 创建KNN分类器\n",
    "knn = KNeighborsClassifier(n_neighbors=5, algorithm='auto')  # 创建KNN分类器实例\n",
    "# n_neighbors=5: 设置K值为5，表示分类时考虑最近的5个邻居的投票\n",
    "# algorithm='auto': 设置用于计算最近邻的算法，'auto'表示根据输入数据自动选择最合适的算法\n",
    "# 可选的算法有'ball_tree'、'kd_tree'和'brute'(暴力搜索)\n",
    "# 当数据较小时可能使用暴力搜索，数据量大时可能选择'kd_tree'或'ball_tree'以提高效率\n",
    "\n",
    "# 训练模型\n",
    "knn.fit(X_train, y_train)\n",
    "\n",
    "# 预测\n",
    "y_pred = knn.predict(X_test)\n",
    "\n",
    "# 评估模型\n",
    "accuracy = accuracy_score(y_test, y_pred)\n",
    "print(f\"模型准确率: {accuracy:.4f}\")\n",
    "\n",
    "# KNN的主要参数：\n",
    "# n_neighbors: K值，即考虑的最近邻数量\n",
    "# weights: 权重，可选'uniform'（等权重）或'distance'（距离加权）\n",
    "# algorithm: 计算最近邻的算法，可选'auto', 'ball_tree', 'kd_tree', 'brute'\n",
    "# p: 距离度量，p=1为曼哈顿距离，p=2为欧氏距离\n",
    "\n",
    "# 不同K值的影响\n",
    "k_range = range(1, 31)\n",
    "scores = []\n",
    "for k in k_range:\n",
    "    knn = KNeighborsClassifier(n_neighbors=k)\n",
    "    knn.fit(X_train, y_train)\n",
    "    scores.append(knn.score(X_test, y_test))\n",
    "\n",
    "# 解决中文显示问题\n",
    "import matplotlib.pyplot as plt\n",
    "import matplotlib as mpl\n",
    "\n",
    "# 设置matplotlib使用支持中文的字体\n",
    "plt.rcParams['font.sans-serif'] = ['SimHei']  # 使用黑体\n",
    "plt.rcParams['axes.unicode_minus'] = False    # 解决负号显示问题\n",
    "\n",
    "\n",
    "# 可视化不同K值的准确率\n",
    "plt.figure(figsize=(10, 6))\n",
    "plt.plot(k_range, scores)\n",
    "plt.xlabel('K值')\n",
    "plt.ylabel('准确率')\n",
    "plt.title('KNN: 不同K值的准确率变化')\n",
    "plt.grid(True)\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "读取Facebook位置数据集\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>row_id</th>\n",
       "      <th>x</th>\n",
       "      <th>y</th>\n",
       "      <th>accuracy</th>\n",
       "      <th>time</th>\n",
       "      <th>place_id</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>0</td>\n",
       "      <td>0.7941</td>\n",
       "      <td>9.0809</td>\n",
       "      <td>54</td>\n",
       "      <td>470702</td>\n",
       "      <td>8523065625</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>1</td>\n",
       "      <td>5.9567</td>\n",
       "      <td>4.7968</td>\n",
       "      <td>13</td>\n",
       "      <td>186555</td>\n",
       "      <td>1757726713</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>2</td>\n",
       "      <td>8.3078</td>\n",
       "      <td>7.0407</td>\n",
       "      <td>74</td>\n",
       "      <td>322648</td>\n",
       "      <td>1137537235</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>3</td>\n",
       "      <td>7.3665</td>\n",
       "      <td>2.5165</td>\n",
       "      <td>65</td>\n",
       "      <td>704587</td>\n",
       "      <td>6567393236</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>4</td>\n",
       "      <td>4.0961</td>\n",
       "      <td>1.1307</td>\n",
       "      <td>31</td>\n",
       "      <td>472130</td>\n",
       "      <td>7440663949</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   row_id       x       y  accuracy    time    place_id\n",
       "0       0  0.7941  9.0809        54  470702  8523065625\n",
       "1       1  5.9567  4.7968        13  186555  1757726713\n",
       "2       2  8.3078  7.0407        74  322648  1137537235\n",
       "3       3  7.3665  2.5165        65  704587  6567393236\n",
       "4       4  4.0961  1.1307        31  472130  7440663949"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 导入必要的库\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "from sklearn.preprocessing import StandardScaler\n",
    "from sklearn.neighbors import KNeighborsClassifier\n",
    "from sklearn.model_selection import train_test_split\n",
    "from datetime import datetime\n",
    "\n",
    "# 读取Facebook位置数据集\n",
    "print('读取Facebook位置数据集')\n",
    "fb_train = pd.read_csv('./FBlocation/train.csv')\n",
    "fb_train.head()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "将time列转换为年月日时分秒格式...\n",
      "样本数量：29118021\n",
      "特征数量：10\n",
      "   row_id       x       y  accuracy    time    place_id      time_formatted  \\\n",
      "0       0  0.7941  9.0809        54  470702  8523065625 1970-01-06 10:45:02   \n",
      "1       1  5.9567  4.7968        13  186555  1757726713 1970-01-03 03:49:15   \n",
      "2       2  8.3078  7.0407        74  322648  1137537235 1970-01-04 17:37:28   \n",
      "3       3  7.3665  2.5165        65  704587  6567393236 1970-01-09 03:43:07   \n",
      "4       4  4.0961  1.1307        31  472130  7440663949 1970-01-06 11:08:50   \n",
      "\n",
      "   weekday  hour  day  \n",
      "0        1    10    6  \n",
      "1        5     3    3  \n",
      "2        6    17    4  \n",
      "3        4     3    9  \n",
      "4        1    11    6  \n"
     ]
    }
   ],
   "source": [
    "# 将time列转换为时分秒\n",
    "# 将time列从秒数转换为时分秒\n",
    "print('将time列转换为年月日时分秒格式...')\n",
    "# 时间是Unix时间戳，需要转换为年月日时分秒格式\n",
    "# 这行代码将'time'列中的Unix时间戳（以秒为单位）转换为pandas的datetime格式\n",
    "# pd.to_datetime()函数将数值转换为datetime对象\n",
    "# unit='s'参数指定输入的时间单位是秒\n",
    "# 转换后的日期时间被存储在新列'time_formatted'中，便于后续分析和可视化\n",
    "fb_train['time_formatted'] = pd.to_datetime(fb_train['time'], unit='s')\n",
    "\n",
    "# 从时间中提取星期几、小时、天作为新特征\n",
    "\n",
    "fb_train['weekday'] = fb_train['time_formatted'].dt.dayofweek  # 从time_formatted列中提取星期几信息（0-6，0表示周一，6表示周日）\n",
    "fb_train['hour'] = fb_train['time_formatted'].dt.hour # 从time_formatted列中提取小时信息（0-23）\n",
    "fb_train['day'] = fb_train['time_formatted'].dt.day # 从time_formatted列中提取天信息（1-31）\n",
    "\n",
    "# 显示数据集基本信息\n",
    "print(f'样本数量：{fb_train.shape[0]}')  # 总共多少行\n",
    "print(f'特征数量：{fb_train.shape[1]}')  # 总共多少列\n",
    "\n",
    "print(fb_train.head())\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "检查缺失值...\n",
      "row_id            0\n",
      "x                 0\n",
      "y                 0\n",
      "accuracy          0\n",
      "time              0\n",
      "place_id          0\n",
      "time_formatted    0\n",
      "weekday           0\n",
      "hour              0\n",
      "day               0\n",
      "dtype: int64\n"
     ]
    }
   ],
   "source": [
    "# 检查缺失值\n",
    "print('检查缺失值...')\n",
    "print(fb_train.isnull().sum())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "筛选后的样本数量：17710\n",
      "筛选前的样本数量：29118021\n",
      "筛选比例：0.00\n"
     ]
    }
   ],
   "source": [
    "# 根据x和y特征列的数值筛选数据\n",
    "\n",
    "filterer_fb_train = fb_train.query('x > 1.0 & x < 1.25 & y > 2.5 & y < 2.75')\n",
    "\n",
    "# 查看筛选后的数据集基本信息\n",
    "print(f'筛选后的样本数量：{filterer_fb_train.shape[0]}')\n",
    "print(f'筛选前的样本数量：{fb_train.shape[0]}')\n",
    "\n",
    "# 查看筛选比例\n",
    "print(f'筛选比例：{filterer_fb_train.shape[0]/fb_train.shape[0]:.2f}')\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "统计每个place_id出现的次数...\n",
      "前10个最常出现的place_id:\n",
      "place_id\n",
      "1097200869    1044\n",
      "6683426742     894\n",
      "3312463746     889\n",
      "4932578245     863\n",
      "5606572086     656\n",
      "8048985799     651\n",
      "6424972551     594\n",
      "5270522918     539\n",
      "3992589015     533\n",
      "2355236719     486\n",
      "Name: count, dtype: int64\n",
      "筛选前数据量: 29118021\n",
      "筛选后数据量: 16918\n",
      "保留比例: 0.05810%\n"
     ]
    }
   ],
   "source": [
    "# 统计每个place_id出现的次数\n",
    "print('统计每个place_id出现的次数...')\n",
    "# 这行代码统计数据集中每个place_id出现的频次\n",
    "# fb_train['place_id']选择数据框中的place_id列\n",
    "# value_counts()方法计算该列中每个唯一值出现的次数，并返回一个Series\n",
    "# 返回的Series以place_id为索引，出现次数为值，默认按照出现次数降序排列\n",
    "# 这有助于了解哪些地点最受欢迎或访问频率最高\n",
    "place_counts = filterer_fb_train['place_id'].value_counts()\n",
    "\n",
    "# 显示前10个最常出现的place_id\n",
    "print(\"前10个最常出现的place_id:\")\n",
    "print(place_counts.head(10))\n",
    "type(place_counts)\n",
    "\n",
    "# 筛选出出现次数大于3的place_id\n",
    "# 这行代码筛选出在数据集中出现次数大于3次的place_id\n",
    "# place_counts是一个Series，索引是place_id，值是每个place_id出现的次数\n",
    "# place_counts > 3创建一个布尔掩码，标记出现次数大于3的place_id\n",
    "# place_counts[place_counts > 3]使用这个掩码筛选Series，得到符合条件的子集\n",
    "# .index获取这个子集的索引，即所有出现次数大于3的place_id\n",
    "# 注意：这里得到的vaild_place_id是一个Index对象，不能使用.head()方法\n",
    "vaild_place_id = place_counts[place_counts > 3].index\n",
    "\n",
    "# 只保留出现次数大于3的place_id对应的数据\n",
    "# 使用isin方法筛选出place_id在vaild_place_id中的行\n",
    "# 这行代码创建一个新的DataFrame，只包含place_id出现次数大于3的记录\n",
    "filtered_fb_train = filterer_fb_train[filterer_fb_train['place_id'].isin(vaild_place_id)]\n",
    "\n",
    "# 显示筛选前后的数据量对比\n",
    "print(f\"筛选前数据量: {fb_train.shape[0]}\")\n",
    "print(f\"筛选后数据量: {filtered_fb_train.shape[0]}\")\n",
    "print(f\"保留比例: {filtered_fb_train.shape[0]/fb_train.shape[0]:.5%}\")\n",
    "\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "               x       y  accuracy  weekday  hour  day\n",
      "21946878  1.0372  2.7066        68        2    16    7\n",
      "24421903  1.0292  2.5471        72        2    17    7\n",
      "8212594   1.0001  2.6381         5        3     4    8\n",
      "2438397   1.1467  2.6501       380        4    12    9\n",
      "24002586  1.0438  2.6610        68        5    11    3\n",
      "对特征进行标准化处理\n"
     ]
    }
   ],
   "source": [
    "# 提取特征和标签，加入新提取的时间特征\n",
    "X = filtered_fb_train[['x', 'y', 'accuracy', 'weekday', 'hour', 'day']] # 特征列\n",
    "y = filtered_fb_train['place_id'] # 标签列\n",
    "\n",
    "# 划分训练集和测试集\n",
    "# 使用train_test_split函数将数据集划分为训练集和测试集\n",
    "# X_train: 用于训练的特征数据，包含70%的样本\n",
    "# X_test: 用于测试的特征数据，包含30%的样本\n",
    "# y_train: 用于训练的标签数据，对应X_train\n",
    "# y_test: 用于测试的标签数据，对应X_test\n",
    "# test_size=0.3: 设置测试集占总数据的30%\n",
    "# random_state=42: 设置随机种子，确保每次运行得到相同的划分结果，便于复现\n",
    "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)\n",
    "\n",
    "print(X_train.head())\n",
    "\n",
    "print('对特征进行标准化处理')\n",
    "\n",
    "# 创建StandardScaler对象，用于特征标准化\n",
    "scaler = StandardScaler()\n",
    "\n",
    "# 对训练集进行拟合和转换\n",
    "# fit_transform方法首先学习训练数据的均值和标准差，然后将数据标准化\n",
    "# 标准化公式: (x - mean) / std\n",
    "# 这样处理后，每个特征的均值为0，标准差为1\n",
    "X_train_scaled = scaler.fit_transform(X_train)\n",
    "\n",
    "# 对测试集仅进行转换，使用从训练集学到的均值和标准差\n",
    "# 这确保了测试集的转换与训练集一致，避免数据泄露\n",
    "\n",
    "X_test_scaled = scaler.transform(X_test)\n",
    "# fit_transform和transform的区别说明\n",
    "# 1. fit_transform:\n",
    "#    - 首先对数据进行拟合(fit)，计算数据的统计信息(如均值、标准差)\n",
    "#    - 然后使用这些统计信息对数据进行转换(transform)\n",
    "#    - 通常用于训练集，因为我们需要从训练集学习统计特性\n",
    "#    - 等价于先调用fit()，再调用transform()\n",
    "\n",
    "# 2. transform:\n",
    "#    - 仅使用已经计算好的统计信息对数据进行转换\n",
    "#    - 不会重新计算统计信息，而是使用之前fit过程中得到的参数\n",
    "#    - 通常用于测试集或新数据，确保它们与训练集使用相同的转换参数\n",
    "#    - 这样可以避免数据泄露，保证模型评估的公正性\n",
    "\n",
    "# 为什么测试集要用transform而不是fit_transform:\n",
    "# - 如果对测试集使用fit_transform，会基于测试集自身的统计特性进行转换\n",
    "# - 这会导致测试数据的转换方式与训练数据不一致\n",
    "# - 模型在实际应用时会收到与训练时不同分布的数据，影响性能\n",
    "# - 使用相同的转换参数确保了特征空间的一致性\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "训练集样本数量11842\n",
      "测试集样本数量5076\n",
      "训练集特征数量6\n",
      "测试集特征数量6\n",
      "训练集标签数量11842\n",
      "测试集标签数量5076\n",
      "239\n"
     ]
    }
   ],
   "source": [
    "print(f'训练集样本数量{X_train.shape[0]}')\n",
    "print(f'测试集样本数量{X_test.shape[0]}')\n",
    "print(f'训练集特征数量{X_train.shape[1]}')\n",
    "print(f'测试集特征数量{X_test.shape[1]}')\n",
    "print(f'训练集标签数量{y_train.shape[0]}')\n",
    "print(f'测试集标签数量{y_test.shape[0]}')\n",
    "# 统计标签的唯一值数量\n",
    "print(y.nunique())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'numpy.ndarray'>\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "array([[-1.1082189 ,  1.05973361, -0.12777082, -0.6631113 ,  0.64727753,\n",
       "         0.7028132 ],\n",
       "       [-1.21199425, -1.2217216 , -0.09169528, -0.6631113 ,  0.79097137,\n",
       "         0.7028132 ],\n",
       "       [-1.58947709,  0.07992369, -0.69596047, -0.063221  , -1.07704854,\n",
       "         1.07057044],\n",
       "       [ 0.31220622,  0.25156922,  2.68612083,  0.5366693 ,  0.07250217,\n",
       "         1.43832767],\n",
       "       [-1.02260423,  0.40748058, -0.12777082,  1.1365596 , -0.07119167,\n",
       "        -0.76821573]])"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "print(type(X_train_scaled))\n",
    "X_train_scaled[0:5]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "KNN模型准确率: 0.4766\n",
      "模型训练和预测总耗时: 0.2872 秒\n",
      "knn模型训练和评估完成！\n"
     ]
    }
   ],
   "source": [
    "# 导入KNN分类器和计时工具\n",
    "from sklearn.neighbors import KNeighborsClassifier\n",
    "import time\n",
    "\n",
    "# 创建KNN分类器实例，设置k=5（可以根据需要调整）\n",
    "knn = KNeighborsClassifier(n_neighbors=5)\n",
    "\n",
    "# 记录开始时间\n",
    "start_time = time.time()\n",
    "\n",
    "# 使用标准化后的训练数据拟合模型\n",
    "knn.fit(X_train_scaled, y_train)\n",
    "\n",
    "# 使用模型对测试数据进行预测\n",
    "y_pred = knn.predict(X_test_scaled)\n",
    "\n",
    "\n",
    "# 计算并记录总耗时\n",
    "end_time = time.time()\n",
    "total_time = end_time - start_time\n",
    "\n",
    "# 计算模型准确率\n",
    "from sklearn.metrics import accuracy_score\n",
    "accuracy = accuracy_score(y_test, y_pred)\n",
    "\n",
    "# 输出结果\n",
    "print(f\"KNN模型准确率: {accuracy:.4f}\")\n",
    "print(f\"模型训练和预测总耗时: {total_time:.4f} 秒\")\n",
    "\n",
    "print('knn模型训练和评估完成！')\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 模型的选择与调优"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "交叉验证与网格搜索...\n",
      "Fitting 5 folds for each of 120 candidates, totalling 600 fits\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\model_selection\\_split.py:811: UserWarning: The least populated class in y has only 1 members, which is less than n_splits=5.\n",
      "  warnings.warn(\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "最佳参数: {'metric': 'manhattan', 'n_neighbors': np.int64(8), 'weights': 'distance'}\n",
      "最佳交叉验证得分: 0.4992\n",
      "网格搜索总耗时: 33.5451 秒\n",
      "最佳KNN模型在测试集上的准确率: 0.5126\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\model_selection\\_split.py:811: UserWarning: The least populated class in y has only 1 members, which is less than n_splits=5.\n",
      "  warnings.warn(\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\model_selection\\_split.py:811: UserWarning: The least populated class in y has only 1 members, which is less than n_splits=5.\n",
      "  warnings.warn(\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\model_selection\\_split.py:811: UserWarning: The least populated class in y has only 1 members, which is less than n_splits=5.\n",
      "  warnings.warn(\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\model_selection\\_split.py:811: UserWarning: The least populated class in y has only 1 members, which is less than n_splits=5.\n",
      "  warnings.warn(\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\model_selection\\_split.py:811: UserWarning: The least populated class in y has only 1 members, which is less than n_splits=5.\n",
      "  warnings.warn(\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\model_selection\\_split.py:811: UserWarning: The least populated class in y has only 1 members, which is less than n_splits=5.\n",
      "  warnings.warn(\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\model_selection\\_split.py:811: UserWarning: The least populated class in y has only 1 members, which is less than n_splits=5.\n",
      "  warnings.warn(\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\model_selection\\_split.py:811: UserWarning: The least populated class in y has only 1 members, which is less than n_splits=5.\n",
      "  warnings.warn(\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\model_selection\\_split.py:811: UserWarning: The least populated class in y has only 1 members, which is less than n_splits=5.\n",
      "  warnings.warn(\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\model_selection\\_split.py:811: UserWarning: The least populated class in y has only 1 members, which is less than n_splits=5.\n",
      "  warnings.warn(\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\model_selection\\_split.py:811: UserWarning: The least populated class in y has only 1 members, which is less than n_splits=5.\n",
      "  warnings.warn(\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\model_selection\\_split.py:811: UserWarning: The least populated class in y has only 1 members, which is less than n_splits=5.\n",
      "  warnings.warn(\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\model_selection\\_split.py:811: UserWarning: The least populated class in y has only 1 members, which is less than n_splits=5.\n",
      "  warnings.warn(\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\model_selection\\_split.py:811: UserWarning: The least populated class in y has only 1 members, which is less than n_splits=5.\n",
      "  warnings.warn(\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\model_selection\\_split.py:811: UserWarning: The least populated class in y has only 1 members, which is less than n_splits=5.\n",
      "  warnings.warn(\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\model_selection\\_split.py:811: UserWarning: The least populated class in y has only 1 members, which is less than n_splits=5.\n",
      "  warnings.warn(\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\model_selection\\_split.py:811: UserWarning: The least populated class in y has only 1 members, which is less than n_splits=5.\n",
      "  warnings.warn(\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\model_selection\\_split.py:811: UserWarning: The least populated class in y has only 1 members, which is less than n_splits=5.\n",
      "  warnings.warn(\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\model_selection\\_split.py:811: UserWarning: The least populated class in y has only 1 members, which is less than n_splits=5.\n",
      "  warnings.warn(\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\model_selection\\_split.py:811: UserWarning: The least populated class in y has only 1 members, which is less than n_splits=5.\n",
      "  warnings.warn(\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n",
      "d:\\Program Files\\Python312\\Lib\\site-packages\\sklearn\\utils\\_response.py:203: UserWarning: The number of unique classes is greater than 50% of the number of samples.\n",
      "  target_type = type_of_target(classes)\n"
     ]
    },
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 1000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "交叉验证与网格搜索完成！\n"
     ]
    }
   ],
   "source": [
    "# 交叉验证与网格搜索\n",
    "print('交叉验证与网格搜索...')\n",
    "# 导入交叉验证和网格搜索工具\n",
    "from sklearn.model_selection import GridSearchCV, cross_val_score\n",
    "from sklearn.neighbors import KNeighborsClassifier\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "# 定义要测试的参数网格\n",
    "param_grid = {\n",
    "    'n_neighbors': np.arange(1, 21),  # 测试1到20的邻居数\n",
    "    'weights': ['uniform', 'distance'],  # 测试两种权重函数\n",
    "    # 'uniform': 所有邻居的权重相等，每个邻居对预测结果的贡献相同\n",
    "    # 'distance': 邻居的权重与其距离成反比，距离越近的邻居权重越大，影响越大\n",
    "    # 这个参数决定了在KNN算法中如何根据距离加权计算预测结果\n",
    "    'metric': ['euclidean', 'manhattan', 'minkowski']  # 测试不同的距离度量\n",
    "    # 'euclidean': 欧几里得距离，计算两点间的直线距离，适用于连续数据，公式为 sqrt(sum((x_i - y_i)^2))\n",
    "    # 'manhattan': 曼哈顿距离，计算两点在各维度上差值的绝对值之和，对异常值不敏感，公式为 sum(|x_i - y_i|)\n",
    "    # 'minkowski': 明可夫斯基距离，是欧几里得和曼哈顿距离的泛化形式，有参数p，当p=1时为曼哈顿距离，p=2时为欧几里得距离\n",
    "}\n",
    "\n",
    "# 创建网格搜索对象\n",
    "grid_search = GridSearchCV(  # 创建网格搜索对象，用于自动寻找最佳参数组合\n",
    "    KNeighborsClassifier(),  # 指定要优化的基础模型是KNN分类器\n",
    "    param_grid,  # 传入前面定义的参数网格，包含要测试的各种参数组合\n",
    "    cv=5,  # 5折交叉验证，将训练数据分成5份，轮流使用其中4份训练，1份验证\n",
    "    scoring='accuracy',  # 使用准确率作为评估指标\n",
    "    n_jobs=-1,  # 使用所有可用的CPU核心进行并行计算，加速搜索过程\n",
    "    verbose=1  # 设置详细程度为1，会显示一些进度信息\n",
    ")\n",
    "\n",
    "# 记录开始时间\n",
    "start_time = time.time()\n",
    "\n",
    "# 执行网格搜索\n",
    "grid_search.fit(X_train_scaled, y_train)\n",
    "\n",
    "# 计算并记录总耗时\n",
    "end_time = time.time()\n",
    "grid_search_time = end_time - start_time\n",
    "\n",
    "# 输出最佳参数和得分\n",
    "print(f\"最佳参数: {grid_search.best_params_}\")\n",
    "print(f\"最佳交叉验证得分: {grid_search.best_score_:.4f}\")\n",
    "print(f\"网格搜索总耗时: {grid_search_time:.4f} 秒\")\n",
    "\n",
    "# 使用最佳参数创建模型\n",
    "best_knn = grid_search.best_estimator_\n",
    "\n",
    "# 在测试集上评估最佳模型\n",
    "y_pred_best = best_knn.predict(X_test_scaled)\n",
    "best_accuracy = accuracy_score(y_test, y_pred_best)\n",
    "print(f\"最佳KNN模型在测试集上的准确率: {best_accuracy:.4f}\")\n",
    "\n",
    "# 可视化不同k值的性能（保持其他最佳参数不变）\n",
    "k_range = np.arange(1, 21)\n",
    "k_scores = []\n",
    "\n",
    "best_weights = grid_search.best_params_['weights']\n",
    "best_metric = grid_search.best_params_['metric']\n",
    "\n",
    "for k in k_range:\n",
    "    knn = KNeighborsClassifier(n_neighbors=k, weights=best_weights, metric=best_metric)\n",
    "    scores = cross_val_score(knn, X_train_scaled, y_train, cv=5, scoring='accuracy')\n",
    "    k_scores.append(scores.mean())\n",
    "\n",
    "# 绘制k值与准确率的关系图\n",
    "plt.figure(figsize=(10, 6))\n",
    "plt.plot(k_range, k_scores, 'o-')\n",
    "plt.xlabel('K值 (邻居数)')\n",
    "plt.ylabel('交叉验证准确率')\n",
    "plt.title('不同K值的KNN模型性能')\n",
    "plt.grid(True)\n",
    "plt.show()\n",
    "\n",
    "print('交叉验证与网格搜索完成！')\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
